package com.cml.learn.netty.http.server;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;

public class HttpHandler extends SimpleChannelInboundHandler<HttpObject> {

	private HttpRequest request;
	private StringBuffer responseMsg = new StringBuffer();

	private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk

	private HttpPostRequestDecoder decoder;

	public HttpHandler() {
		System.out.println("init http handler!HttpHandler!====>threadId:" + Thread.currentThread().getId());
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		if (decoder != null) {
			decoder.cleanFiles();
		}
		System.out.println("channel 关闭！====>threadId:" + Thread.currentThread().getId());
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
		if (msg instanceof HttpRequest) {
			HttpRequest request = this.request = (HttpRequest) msg;
			URI uri = new URI(request.uri());
			System.err.println("request uri==" + uri.getPath());

			if (uri.getPath().equals("/favicon.ico")) {
				return;
			}

			// get请求，直接关闭
			if (request.method().equals(HttpMethod.GET)) {
				QueryStringDecoder decoderQuery = new QueryStringDecoder(uri);
				Map<String, List<String>> uriAttributes = decoderQuery.parameters();
				for (Entry<String, List<String>> attr : uriAttributes.entrySet()) {
					for (String attrVal : attr.getValue()) {
						System.out.println("URI: " + attr.getKey() + '=' + attrVal + "\r\n");
					}
				}
				responseMsg.append("getMethod Response!" + uriAttributes + ",当前线程：" + Thread.currentThread().getId());
				writeMsg(ctx);
				return;
			}

			// 判断request请求是否是post请求
			if (request.method().equals(HttpMethod.POST)) {
				try {
					/**
					 * 通过HttpDataFactory和request构造解码器
					 */
					decoder = new HttpPostRequestDecoder(factory, request);
				} catch (ErrorDataDecoderException e1) {
					e1.printStackTrace();
					responseMsg.append("post执行出错了！" + e1.getMessage());
					ctx.channel().close();
					return;
				}

			}
		}

		if ((msg instanceof HttpContent) && decoder != null) {
			// New chunk is received
			HttpContent chunk = (HttpContent) msg;
			try {
				decoder.offer(chunk);

				responseMsg.append("======================参数=============\n");
				while (decoder.hasNext()) {
					InterfaceHttpData data = decoder.next();
					if (data != null) {
						try {
							writeHttpData(data);
						} finally {
							data.release();
						}
					}
				}

			} catch (Exception e1) {
				System.out.println("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n 处理结束");
			}
			responseMsg.append("======================参数=============\n");
			writeMsg(ctx);

			// example of reading only if at the end
			if (chunk instanceof LastHttpContent) {
				reset();
			}
		}

	}

	private void writeHttpData(InterfaceHttpData data) {
		System.out.println("data.getHttpDataType()==>" + data.getHttpDataType());
		/**
		 * HttpDataType有三种类型 Attribute, FileUpload, InternalAttribute
		 */
		if (data.getHttpDataType() == HttpDataType.Attribute) {
			Attribute attribute = (Attribute) data;
			String value;
			try {
				value = attribute.getValue();
			} catch (IOException e1) {
				e1.printStackTrace();
				System.out.println("\r\n111BODY Attribute: " + attribute.getHttpDataType().name() + ":" + attribute.getName()
						+ " Error while reading value: " + e1.getMessage() + "\r\n");
				return;
			}

			responseMsg.append(attribute.getName()).append(":");
			responseMsg.append(value).append("\n");
		}
	}

	private void reset() {
		request = null;
		// destroy the decoder to release all resources
		decoder.destroy();
		decoder = null;
		responseMsg.setLength(0);
	}

	private void writeMsg(ChannelHandlerContext ctx) throws Exception {
		System.out.println("response Msg=====>" + responseMsg.toString());
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
				Unpooled.wrappedBuffer(responseMsg.toString().getBytes("UTF-8")));
		response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
		response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
		response.headers().set(HttpHeaderNames.CONTENT_ENCODING, "utf-8");
		if (HttpUtil.isKeepAlive(request)) {
			response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
		}
		//输出并且关闭连接
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

}
